package language.advanced.generic;

import lombok.Data;

//奇异递归泛型(curiously recurring generics, CRG )
//“奇异递归”指的是你的类奇怪地在自身的基类中出现的现象
@Data
class SelfBoundA<T> {
    //主要是起到限定的作用，让
    //任何一个继承了Cycle<T>的类里面的方法（如get和set方法）的返回类型必须是子类型
    //比如如果CycleB extends Cycle<CycleB>，那么方法T element的返回类型必须是CycleB的子类型
    private T element;

    //测试方法
    public void f(){
        System.out.println(element.getClass().getSimpleName());
    }
}
class CycleA extends SelfBoundA<CycleA>{}
class CycleB {}
class CycleC extends SelfBoundA<CycleB>{}
//这种写法有一个问题， class Cycle<T> 里面的T如果被设置成别的类比如class CycleB extends Cycle<Apple>
//那么就失去了限定的意义。全靠开发人员的自觉


//CycleB extends SelfBounded<CycleB> 观察并抽出特定的类型为
//     T extends SelfBounded<T>
class SelfBoundB<T extends SelfBoundB<T>>{ } //自限定类型是指将自身作为泛型参数的边界类型
class CycleD extends SelfBoundB<CycleD>{} //限制了在使用了泛型的函数中，返回或者入参只能是CycleD
//class CycleE extends SelfBoundB<CycleB>{} //无法通过编译，因为CycleB没有继承自SelfBoundB
class CycleF extends SelfBoundB<CycleD>{} //可以，因为CycleD是继承自SelfBoundB的

//它强制任何使用该类的人都遵从这种形式
//SelfBoundB类中的函数返回类型或者参数的类型 只能是SelfBoundB的子类；
//JDK应用实例：public abstract class Enum<E extends Enum<E>>

//"自限定类型"（Self-bounded Type）

//也可以将自限定用于泛型方法:
//public static <T extends SelfBoundB<T>> void process(T obj) {
//    obj.foo();
//}
//如果没有使用自限定，普通的继承机制就会介入，并旦会进行重载
